package cn.good.yan.sf.t6.blocking;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 6 阻塞队列 - 单锁实现 1
 *
 * @author shengren.yan
 * @create 2024-07-22
 */
@SuppressWarnings("all")
public class BlockQueue1<E> implements BlockingQueue<E> {


    E[] arr;
    int head;
    int tail;
    int size;

    public BlockQueue1(int num) {
        arr = (E[]) new Object[num];
    }

    Lock lock = new ReentrantLock();
    Condition headCon = lock.newCondition();
    Condition tailCon = lock.newCondition();

    // 0 1 2 3 4
    @Override
    public void offer(E e) throws InterruptedException {
        lock.lockInterruptibly(); // 加锁，可以在阻塞状态随时打断
        try {
            if (isFull()) {
                tailCon.await();
            }
            arr[tail] = e;
            if (++tail == arr.length) {
                tail = 0;
            }
            size++;
            headCon.signal();
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean offer(E e, long timeout) throws InterruptedException {
        lock.lockInterruptibly();
        try {
            long t = TimeUnit.MILLISECONDS.toNanos(timeout);
            while (isFull()) {
                if (t < 0) {
                    System.out.println(e + "等待超时：" + t);
                    return false;
                }
                t = tailCon.awaitNanos(t);
            }
            arr[tail] = e;
            if (tail++ == arr.length - 1) {
                tail = 0;
            }
            size++;
            headCon.signal();
        } finally {
            lock.unlock();
        }
        return true;
    }

    @Override
    public E pool() throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (isEmpty()) {
                headCon.await();
            }
            E e = arr[head];
            arr[head] = null;
            if (++head == arr.length) {
                head = 0;
            }
            size--;
            tailCon.signal();
            return e;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean isFull() {
        return size == arr.length;
    }

    @Override
    public String toString() {
        return "BlockQueue1{" +
                "arr=" + Arrays.toString(arr) +
                '}';
    }

    public static void main(String[] args) throws InterruptedException {
        // 流程 ： 有3个位置， 1 2 3 添加， 添加4 被阻塞， 等1移出后，4被添加到队列中
        BlockQueue1<String> q = new BlockQueue1<>(3);

        new Thread(() -> {
            System.out.println(System.currentTimeMillis() + " 开始 ");
            try {
                q.offer("任务1");
                System.out.println("1----" + q);
                q.offer("任务2");
                System.out.println("2----" + q);
                q.offer("任务3");
                System.out.println("3----" + q);
                q.offer("任务4", 100);
                System.out.println("4----" + q);
                q.offer("任务5");
                System.out.println("5----" + q);
                q.offer("任务6");
                System.out.println("6----" + q);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(System.currentTimeMillis() + " 结束 ");
        }, "线程A").start();

        Thread.sleep(2000);

        new Thread(() -> {
            try {
                System.out.println("移除一个值：" + q.pool());
                System.out.println("移除一个值：" + q.pool());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("");
        }, "线程B").start();


    }

}
